﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

using Qas.CommonLogic.BusinessObjects;

namespace Qas.CommonLogic
{
    /// <summary>
    /// Условие - основной элемент системы; условия определяют 
    /// результаты работы задачи и может ли она стартовать
    /// </summary>
    public partial class Condition : AbstractObject
    {
        private double conditionAccessibility = 0;
        private Condition cloneFromBase = null;

        private List<Task> producingTasks = new List<Task>();

        [System.Xml.Serialization.XmlIgnore()]
        public List<Task> ProducingTasks
        {
            get
            {
                return this.producingTasks;
            }
        }

        public override string ToString()
        {
            // Текстовое представление элемента класса Условие
            if (string.IsNullOrEmpty(this.Title))
            {
                this.Title = Base.CurrBase.GetConditionById(this.ID).Title;
            }

            return this.ID + ": " + this.Title;
        }

        public static List<Condition> Summation(List<Condition> firstlist, List<Task> tasklist)
        {
            List<Condition> AllSum = new List<Condition>();

            foreach (Task task in tasklist)
            {
                AllSum.AddRange(task.PreConditions);
            }
            AllSum.AddRange(firstlist);
            return AllSum;
        }

        public override bool Equals(object obj)
        {
            // Мы можем сравнивать Условия только с другими условиями
            // Сравнение с объектами другого типа некорректно, и они априори неравны
            if (obj is Condition)
            {
                Condition objCond = obj as Condition;
                return (objCond.ID == this.ID);
            }

            return false;
        }

        public void Evaluate(List<Task> tasks)
        {
            if (this.cloneFromBase == null)
            {
                List<Condition> availableConditions = Base.CurrBase.AvailableConditions;
                foreach (Condition conditionItem in availableConditions)
                {
                    if (conditionItem.ID == this.ID)
                    {
                        this.cloneFromBase = conditionItem;
                    }
                }
            }
            // Значение по умолчанию, если уж пересчитывать значение, то с нуля
            this.conditionAccessibility = 0;
            foreach (Task taskItem in tasks)
            {
                if (taskItem.PostConditions.Contains(this))
                {
                    this.ProducingTasks.Add(taskItem);
                    this.conditionAccessibility++;
                }
            }
        }

        public void Done(List<Task> tasks)
        {
            if (this.producingTasks.Count == 0)
            {
                foreach (Task task in tasks)
                {
                    if (task.PostConditions.Contains(this))
                    {
                        this.producingTasks.Add(task);
                    }
                }
            }

            foreach (Task prodTask in this.producingTasks)
            {
                prodTask.Value -= 1 / this.Accessibility;
            }
        }

        public void UnDone(List<Task> tasks)
        {
            if (this.producingTasks.Count == 0)
            {
                foreach (Task task in tasks)
                {
                    if (task.PostConditions.Contains(this))
                    {
                        this.producingTasks.Add(task);
                    }
                }
            }

            foreach (Task prodTask in this.producingTasks)
            {
                prodTask.Value += 1 / this.Accessibility;
            }
        }



        public void ReEvaluate(Task task)
        {
            if (task.PostConditions.Contains(this))
            {
                this.conditionAccessibility--;
            }
        }

        [System.Xml.Serialization.XmlIgnore()]
        public double Accessibility
        {
            get
            {
                if (this.cloneFromBase == null)
                {
                    List<Condition> availableConditions = Base.CurrBase.AvailableConditions;
                    foreach (Condition conditionItem in availableConditions)
                    {
                        if (conditionItem.ID == this.ID)
                        {
                            this.cloneFromBase = conditionItem;
                        }
                    }
                }

                return this.cloneFromBase.conditionAccessibility;
            }
        }

        public override int GetHashCode()
        {
            return this.ID;
        }

        /// <summary>
        /// Суммирование наборов условий: аналог операции объединения множеств
        /// </summary>
        /// <param name="firstList">Первый список</param>
        /// <param name="secondList">Второй список</param>
        /// <returns>Новый набор условий, являющийся объединением наборов-слагаемых</returns>
        public static List<Condition> Summation(List<Condition> firstList, List<Condition> secondList)
        {
            // Создаём слепок первого слагаемого
            List<Condition> result = new List<Condition>();
            result.AddRange(firstList);

            foreach (Condition cond in secondList)
            {
                // Добавляем в результат все элементы второго списка, не входящие в первый
                if (!result.Contains(cond))
                {
                    result.Add(cond);
                }
            }

            return result;
        }

        /// <summary>
        /// Вычитание наборов условий: аналог операции вычетания множеств
        /// </summary>
        /// <param name="firstList">Уменьшаемое</param>
        /// <param name="secondList">Вычитаемое</param>
        /// <returns>Новый набор условий, являющийся результатом вычитания</returns>
        public static List<Condition> Subtraction(List<Condition> firstList, List<Condition> secondList)
        {
            // Делаем слепок уменьшаемого
            List<Condition> result = new List<Condition>();
            result.AddRange(firstList);

            foreach (Condition cond in secondList)
            {
                // Удаляем из результирующего множества все элементы, 
                // присутствующие как в уменьшаемом, так и в вычитаемом
                if (result.Contains(cond))
                {
                    result.Remove(cond);
                }
            }

            return result;
        }
    }
}
